#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WebServer.h>
#include "EEPROM.h"
#include "WiFiManager.h"
#include "ArduinoJson.h"
#include <FastLED.h>
#include <ESP8266HTTPUpdateServer.h> //无线更新固件

WiFiClient client;
WiFiManager wifim; // 配网函数
ESP8266HTTPUpdateServer httpUpdater;  // 无线更新固件
ESP8266WebServer server(80);
const size_t capacity = JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + 70;
DynamicJsonDocument doc(capacity); //
// 测试HTTP请求用的URL
String uid = "";
String topic = "";
String api = "";
const unsigned long HTTP_TIMEOUT = 5000;               // 服务器的最大响应时间

float Prices = 0;   //此变量用于存储获取到的EEPROM浮点型数据 鸡蛋价格
#define PricesAddr   0     //EEPROM地址 -> 价格
#define BrightAddr   2     //EEPROM地址 -> 亮度
#define EEPROM_uid_lenght_Addr   4     //EEPROM地址 -> uid长度数
#define EEPROM_topic_lenght_Addr   6     //EEPROM地址 -> topic长度数
#define EEPROM_uid_Addr   100     //EEPROM地址 -> uid起始位置
#define EEPROM_topic_Addr    200     //EEPROM地址 -> topic起始位置
//********************WS2812B配置*******************//
#define NUM_LEDS 30 /// 灯的数量
#define DATA_PIN 13 /// 输出控制信号引脚 ESP8266 GPIO_13
//#define CLOCK_PIN 13
#define LED_TYPE WS2812B         // LED灯带型号
#define COLOR_ORDER GRB         // RGB灯珠中红色、绿色、蓝色LED的排列顺序

int bright = 20; // LED亮度控制变量 可使用数值为 0 ～ 255
CRGB leds[NUM_LEDS];    // leds
CRGB hcolor = CRGB::Red;
CRGB OFF = CRGB::Black;
int nums[10][14] = {
        {1, 2, 3,  4, 5,  6, 9,  10, 11, 12, 13, 14},
        {5, 6, 13, 14},
        {3, 4, 5,  6, 7,  8, 9,  10, 11, 12},
        {3, 4, 5,  6, 7,  8, 11, 12, 13, 14},
        {1, 2, 5,  6, 7,  8, 13, 14},
        {1, 2, 3,  4, 7,  8, 11, 12, 13, 14},
        {1, 2, 3,  4, 7,  8, 9,  10, 11, 12, 13, 14},
        {3, 4, 5,  6, 13, 14},
        {1, 2, 3,  4, 5,  6, 7,  8,  9,  10, 11, 12, 13, 14},
        {1, 2, 3,  4, 5,  6, 7,  8,  11, 12, 13, 14},
};

void getprice(); // 获取价格
void updatePrice();// 更新价格 同时更新显示
void ws2812_show(float jiage); // 控制显示
String read_config(int len_addr, int addr); // 读取配置文件
void write_config(int len_addr, int addr, const String &str); // 写入配置文件


void handhome();// web页面控制
void onNotFound();// 404页面

void setup() {
    EEPROM.begin(1024); // 开辟eeprom空间
    Serial.begin(115200); // 初始化串口 波特率
    wifim.setConnectTimeout(10);// 等待wifi 延迟 推荐1分钟
    wifim.autoConnect("OLED配网热点"); // 开启配网热点
    Serial.println("配网完成");    // WiFi连接成功后将通过串口监视器输出连接成功信息
    Serial.print("ESP8266连接的WiFi是");
    Serial.println(WiFi.SSID());              // WiFi名称
    delay(100);
    httpUpdater.setup(&server);
    server.on("/", handhome);
    server.onNotFound(onNotFound);
    server.begin(); // web控制面板初始化!
    uid = read_config(EEPROM_uid_lenght_Addr, EEPROM_uid_Addr); // 读取配置文件!
    delay(100);
    topic = read_config(EEPROM_topic_lenght_Addr, EEPROM_topic_Addr); // 读取配置文件!
    delay(100);
    api = "http://apis.bemfa.com/va/getmsg?uid=" + uid + "&topic=" + topic + "&type=3";
    Serial.println(api);
    EEPROM.get(PricesAddr, Prices);    //从EEPROM获取存的数据
    delay(100);
    EEPROM.get(BrightAddr, bright);    //从EEPROM获取存的数据
    delay(100);
    if (Prices != 0) {
        Serial.print("储存的单价：");
        Serial.println(Prices);
    }
    // ws2812b灯带
    LEDS.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);  // 初始化光带
    LEDS.setBrightness(bright);
    client.setTimeout(HTTP_TIMEOUT); // 设置Web延迟
}

void updatePrice() {
    // 更新EEPROM
    EEPROM.put(PricesAddr, Prices);
    EEPROM.commit();
    Serial.print("EEPROM-->保存价格-->");
    Serial.println(Prices);
    // 更新显示
}

void ws2812_show(float jiage) {
    String str = String(jiage, 1); // 要被分割的字符串
    String part1 = str.substring(0, 1); // 获取第一部分
    String part2 = str.substring(2); // 获取第二部分
    int one = part1.toInt();
    int tow = part2.toInt();
    FastLED.clear();
    Serial.print("鸡蛋价格: ");
    Serial.print(one);
    Serial.print("块");
    Serial.println(tow);
    for (int i: nums[one]) {
        if (i != 0) {
            leds[i - 1] = hcolor;
        }
    }
    // 末尾0 就不显示了
    if (tow != 0) {
        leds[29 - 1] = hcolor;
        for (int j: nums[tow]) {
            if (j != 0) {
                leds[j + 14 - 1] = hcolor;
            }
        }
    }
}

void getprice() {
    //创建 HTTPClient 对象
    HTTPClient hc;
    hc.begin(client, api);
    //启动连接并发送HTTP请求
    int httpCode = hc.GET();
    //如果服务器不响应OK则将服务器响应状态码通过串口输出
    if (httpCode == HTTP_CODE_OK) {
        // 序列化
        deserializeJson(doc, hc.getString());
        // 读取 Json
        float tmpPrices = doc["data"][0]["msg"].as<float>();
        Serial.print("[获取价格]--->");
        if (Prices != tmpPrices) {
            Serial.print("[原价格]--->");
            Serial.print(Prices);
            Serial.print("[现价格]--->");
            Serial.print(tmpPrices);
            Prices = tmpPrices;
            updatePrice();
        }
    } else {
        Serial.print("[HTTP_ERROR] HTTPCode Code：");
        Serial.println(httpCode);
    }
    //关闭ESP8266与服务器连接
    hc.end();
}

void write_config(int len_addr, int addr, const String &str) {
    EEPROM.write(len_addr, str.length());
//    EEPROM.write(len_addr, str.length() - 1);
    for (int i = 0; i < (int) str.length(); i++) {
        EEPROM.write(addr + i, str[i]);
    }
    EEPROM.commit();
}

//len_addr位是字符串长度，addr是起始位(字符串首地址)
String read_config(int len_addr, int addr) {
    String data = "";
    int length = EEPROM.read(len_addr);    //读取记录在EEPROM中的数据长度
    //从EEPROM中逐个取出每一位的值，并链接
    for (int i = 0; i < length; i++) {
        data += char(EEPROM.read(addr + i));
    }
    return data;
}

void handhome() {
    if (server.hasArg("uid")) {
        uid = server.arg("uid").c_str();
        topic = server.arg("topic").c_str();
        api = "http://apis.bemfa.com/va/getmsg?uid=" + uid + "&topic=" + topic + "&type=3";
        Serial.println("保存");
        Serial.println(api);
        write_config(EEPROM_uid_lenght_Addr, EEPROM_uid_Addr, uid);
        write_config(EEPROM_topic_lenght_Addr, EEPROM_topic_Addr, topic);
    } else if (server.hasArg("setbright")) {
        bright = server.arg("setbright").toInt();
        Serial.println("更新亮度");
        Serial.println(bright);
        EEPROM.write(BrightAddr, bright);
        EEPROM.commit();
        delay(100);
    }

    String htmlPage = "<html lang='en'>\n"
                      "<head>\n"
                      "    <title>配置页面</title>\n"
                      "</head>\n"
                      "<style>\n"
                      "    .form {\n"
                      "        text-align: center;\n"
                      "    }\n"
                      "</style>\n"
                      "<script>\n"
                      "    function update() {\n"
                      "        const uid = document.getElementById('uid').value;\n"
                      "        const topic = document.getElementById('topic').value;\n"
                      "        const ajax = new XMLHttpRequest();\n"
                      "        ajax.open('GET', window.location.origin + '/?uid=' + uid + '&topic=' + topic, true);\n"
                      "        ajax.send(null);\n"
                      "    }\n"
                      "    function setbright(bright) {\n"
                      "        const ajax = new XMLHttpRequest();\n"
                      "        ajax.open('GET', window.location.origin + '/?setbright=' + bright, true);\n"
                      "        ajax.send(null);\n"
                      "    }"
                      "</script>\n"
                      "<body>\n"
                      "<div class='form'>\n"
                      "    <form>\n"
                      "        <label>\n"
                      "            uid:<input id='uid' type='text' value='"
                      + uid
                      + "'>\n"
                        "        </label>\n"
                        "        <br>\n"
                        "        <label>\n"
                        "            topic:<input id='topic' type='text' value='"
                      + topic
                      + "'>\n"
                        "        </label>\n"
                        "        <br>\n"
                        "        <span>亮度</span>\n"
                        "        <label for='setbriht'>\n"
                        "        </label><input type='range' id='setbriht' max='100' min='5' onchange='setbright(this.value)' value='"
                      + bright
                      +
                      "'>\n"
                      "        <br>"
                      "        <button onclick='update()'>提交\n"
                      "        </button>\n"
                      "    </form>\n"
                      "</div>\n"
                      "\n"
                      "\n"
                      "</body>\n"
                      "</html>";
    server.send(200, "text/html;charset=utf-8", htmlPage);
}

void onNotFound() {
    server.send(404, "text/plain", "404: Not found"); // 发送 HTTP 状态 404 (未找到页面) 并向浏览器发送文字 "404: Not found"
}

void loop() {
    // 每5秒
    EVERY_N_SECONDS(5) {
        // 如果ESP8266连接WiFi则发送HTTP请求
        if ((WiFi.status() == WL_CONNECTED)) {
            getprice();
            hcolor = CRGB::OrangeRed;
        } else {
            hcolor = CRGB::LightGreen;
        }
        ws2812_show(Prices);
    }
    FastLED.setBrightness(bright);
    FastLED.show();
    server.handleClient();
}

